package com.xiguaji.tiktok.v1.web.tiktok.service;

import com.xiguaji.boot.toolkit.DateTimeUtils;
import com.xiguaji.boot.toolkit.JsonUtil;
import com.xiguaji.tiktok.utils.ESUtil;
import com.xiguaji.tiktok.utils.RedisKeysManager;
import com.xiguaji.tiktok.v1.tiktok.aweme.dto.AwemeResponse;
import com.xiguaji.tiktok.v1.tiktok.aweme.model.Aweme;
import com.xiguaji.tiktok.v1.tiktok.aweme.repository.AwemeRepository;
import com.xiguaji.tiktok.v1.tiktok.blogger.dto.BloggerDataResponse;
import com.xiguaji.tiktok.v1.tiktok.blogger.dto.BloggerFansPortraitResponse;
import com.xiguaji.tiktok.v1.tiktok.blogger.dto.BloggerPerformanceResponse;
import com.xiguaji.tiktok.v1.tiktok.blogger.repository.ConfigurationRepository;
import com.xiguaji.tiktok.v1.tiktok.blogger.service.BloggerService;
import com.xiguaji.tiktok.v1.web.tiktok.dto.BloggerInfluencerResponse;
import com.xiguaji.tiktok.v1.web.tiktok.dto.SearchBloggerResponse;
import com.xiguaji.tiktok.v1.web.tiktok.dto.VideoResponse;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class TopTiktokService {
    @Autowired
    RestHighLevelClient client;

    @Autowired
    AwemeRepository awemeRepository;

    @Autowired
    ESUtil esUtil;

    /**
     * 博主服务类
     */
    @Autowired
    BloggerService bloggerService;

    /**
     * 配置dao
     */
    @Autowired
    ConfigurationRepository configurationRepository;

    /**
     * redis服务
     */
    @Autowired
    RedisTemplate<String,String> redisTemplate;

    DecimalFormat df = new DecimalFormat("######0.0");

    /**
     * 博主示例配置名
     */
    private final String EXAMPLE_BLOGGER = "exampleBlogger";

    /**
     * 官网首页达人示例过期时间
     */
    @Value("${tiktok.influencer.blogger.example.expired.day}")
    private int INFLUENCER_BLOGGER_EXAMPLE_EXPIRED_DAY;

    /**
     * tiktok达人列表
     * @param count
     * @param sort
     * @param region
     * @return
     */
    public List<BloggerInfluencerResponse> getBloggersForInfluencer(int count, String sort, String region) {
        List<BloggerInfluencerResponse> bloggerInfluencerResponses = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(ESUtil.BLOGGER_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        if(!StringUtils.isEmpty(region)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("region",region));
        }

        String sortStr = "score";

        switch (sort){
            case "gdindex":
                sortStr = "score";
                break;
            case "followers":
                sortStr = "followerCount";
                break;
            case "likes":
                sortStr = "totalFavorited";
                break;
            case "posts":
                sortStr = "awemeCount";
                break;
            default:
                break;
        }
        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.sort(sortStr, SortOrder.DESC);
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(count);
        searchRequest.source(searchSourceBuilder);

        try{
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            val hits = searchResponse.getHits().getHits();

            for (SearchHit hit : hits) {
                val map = JsonUtil.jsonParse(Map.class,hit.getSourceAsString());
                BloggerInfluencerResponse bloggerInfluencerResponse = new BloggerInfluencerResponse();
                bloggerInfluencerResponse.setUid(map.get("uid").toString());
                bloggerInfluencerResponse.setNickName(map.get("nickName").toString());
                bloggerInfluencerResponse.setUniqueId(map.get("uniqueId").toString());

                String avatar = map.get("avatar168").toString();
                if((avatar.indexOf("sign-sg") > 0 && avatar.indexOf("sign-sg") < 30) || (avatar.indexOf("sign-va") > 0 && avatar.indexOf("sign-va") < 30)){
                    avatar = avatar.replace("sign-sg", "amd-va").replace("sign-va", "amd-va").replace("webp", "jpeg");
                }
                bloggerInfluencerResponse.setAvatar(avatar);
                bloggerInfluencerResponse.setRegion(map.get("region").toString());
                bloggerInfluencerResponse.setAwemeCount(getNumber(Integer.parseInt(map.get("awemeCount").toString())));
                bloggerInfluencerResponse.setScore(getNumber(Double.parseDouble(map.get("score").toString())));
                bloggerInfluencerResponse.setFollowerCount(getNumber(Long.parseLong(map.get("followerCount").toString())));
                bloggerInfluencerResponse.setTotalFavorited(getNumber(Long.parseLong(map.get("totalFavorited").toString())));
                bloggerInfluencerResponse.setAvgView(getNumber(Long.parseLong(map.get("avgViews").toString())));
                bloggerInfluencerResponses.add(bloggerInfluencerResponse);
            }
        }catch (Exception e){
            log.error("es blogger search error!",e);
        }

        return bloggerInfluencerResponses;
    }


    public List<SearchBloggerResponse> searchBlogger(String keyword){
        List<SearchBloggerResponse> bloggerResponses = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(ESUtil.BLOGGER_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        if(!StringUtils.isEmpty(keyword)){
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.should(QueryBuilders.matchQuery("uniqueId",keyword));
            boolQueryBuilder.should(QueryBuilders.matchQuery("nickName",keyword));
            boolQueryBuilder.should(QueryBuilders.wildcardQuery("nickName","*"+keyword+"*"));
            boolQueryBuilder.should(QueryBuilders.wildcardQuery("uniqueId","*"+keyword+"*"));
            boolQueryBuilder.minimumShouldMatch(1);
            searchSourceBuilder.query(boolQueryBuilder);
            searchSourceBuilder.size(10);
        }else {
            searchSourceBuilder.size(5);
        }
        searchSourceBuilder.sort("score", SortOrder.DESC);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;

        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

        val hits = searchResponse.getHits().getHits();

        for (SearchHit hit : hits) {
            SearchBloggerResponse bloggerResponse = new SearchBloggerResponse();
            val map = JsonUtil.jsonParse(Map.class,hit.getSourceAsString());

            if((map.get("avatar168").toString().indexOf("sign-sg") > 0 && map.get("avatar168").toString().indexOf("sign-sg") < 30) || (map.get("avatar168").toString().indexOf("sign-va") > 0 && map.get("avatar168").toString().indexOf("sign-va") < 30)){
                bloggerResponse.setAvatar(map.get("avatar168").toString().replace("sign-sg", "amd-va").replace("sign-va", "amd-va").replace("webp", "jpeg"));
            }
            bloggerResponse.setNickname(map.get("nickName").toString());
            bloggerResponse.setUniqueId(map.get("uniqueId").toString());
            bloggerResponse.setFollowerCount(getNumber(Long.parseLong(map.get("followerCount").toString())));
            bloggerResponse.setEnterpriseVerifyReason(map.get("enterpriseVerifyReason") == null?"":map.get("enterpriseVerifyReason").toString());
            bloggerResponse.setCustomVerify(map.get("customVerify") == null?"":map.get("customVerify").toString());
            bloggerResponse.setUid(Long.parseLong(map.get("uid").toString()));
            bloggerResponse.setRegion(map.get("region").toString());
            bloggerResponses.add(bloggerResponse);
        }
        return bloggerResponses;
    }

    private String formatSecondTimeLive(int val){
        String res = "";
        val = Math.round(val / 1000);
        if (val < 0) {
            val = Math.abs(val);
        }
        int sec = val % 60;
        int min = (int)(Math.floor((val / 60) % 60));
        int hour = (int)(Math.floor(val / 3600));

        String secStr = sec+"";
        String minStr = min+"";
        String hourStr = hour+"";

        if (+sec < 10) {
            secStr = "0"+secStr;
        }

        if (+sec == 0) {
            secStr = "00";
        }

        if (+min < 10) {
            minStr = "0"+min;
        }

        if (+min == 0) {
            minStr = "00";
        }

        if (+hour < 10) {
            hourStr = "0"+hour;
        }

        if (+hour == 0) {
            hourStr = null;
        }

        if (null != hourStr) {
            res = hourStr+":"+minStr+":"+secStr;
        } else {
            res = minStr+":"+secStr;
        }

        return res;
    }


    public List<VideoResponse> getBastVideo(int count, String sort, String type) {
        List<VideoResponse> videoResponses = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(esUtil.getAwemeIndex());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        if(!StringUtils.isEmpty(type)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("awemeType",type));
        }

        boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime")
                .gte(DateTimeUtils.currentTimeSecond()-60*60*24*7));

        String sortKey = "score";

        switch (sort){
            case "spreadIndex":
                sortKey = "score";
                break;
            case "view":
                sortKey = "playCount";
                break;
            case "likes":
                sortKey = "diggCount";
                break;
            case "reviews":
                sortKey = "commentCount";
                break;
            case "share":
                sortKey = "shareCount";
                break;
            default:
                break;
        }

        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.sort(sortKey, SortOrder.DESC);
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(count);
        searchRequest.source(searchSourceBuilder);

        try{
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            val hits = searchResponse.getHits().getHits();

            for (SearchHit hit : hits) {
                val map = JsonUtil.jsonParse(Map.class, hit.getSourceAsString());
                VideoResponse videoResponse = new VideoResponse();
                videoResponse.setAwemeId(map.get("awemeId").toString());
                videoResponse.setTitle(map.get("title").toString());
                videoResponse.setUniqueId(map.get("uniqueId").toString());
                videoResponse.setCover(map.get("cover").toString());
                videoResponse.setDuration(formatSecondTimeLive(Integer.parseInt(map.get("duration").toString())));
                LocalDateTime createDateTime = DateTimeUtils.localDateTimeBySecond(Integer.parseInt(map.get("createTime").toString()));
                videoResponse.setCreateTime(createDateTime.format(DateTimeFormatter.ofPattern("MM-dd-yyyy")));
                videoResponse.setLikes(getNumber(Long.parseLong(map.get("diggCount").toString())));
                videoResponse.setViews(getNumber(Long.parseLong(map.get("playCount").toString())));
                videoResponse.setReviews(getNumber(Long.parseLong(map.get("commentCount").toString())));
                videoResponse.setShare(getNumber(Long.parseLong(map.get("shareCount").toString())));
                videoResponse.setShareUrl(map.get("shareUrl").toString());
                videoResponse.setScore(((int)(Double.parseDouble(map.get("score").toString())*10.0))/10.0);
                BigDecimal dscCount = new BigDecimal(Long.parseLong(map.get("diggCount").toString())
                        +Long.parseLong(map.get("shareCount").toString())+
                        Long.parseLong(map.get("commentCount").toString()));
                BigDecimal playCount = new BigDecimal(Long.parseLong(map.get("playCount").toString()));
                videoResponse.setEngagementRate((dscCount.divide(playCount,3, RoundingMode.FLOOR).multiply(new BigDecimal(100))).setScale(1).doubleValue()+"%");
                videoResponses.add(videoResponse);
            }
        }catch (Exception e){
            log.error("es aweme search error!",e);
        }
        return videoResponses;
    }


    public List<VideoResponse> getVideoByUid(long uid){
        List<Aweme> awemes = awemeRepository.findAwemeByUidOrderByCreateTime(uid,10);
        List<VideoResponse> videoResponses = new ArrayList<>();
        for (Aweme aweme : awemes) {
            if(aweme.getOPlayCount() < 1){
                continue;
            }
            VideoResponse videoResponse = new VideoResponse();
            videoResponse.setAwemeId(String.valueOf(aweme.getOAwemeId()));
            videoResponse.setTitle(aweme.getODesc());
            videoResponse.setUniqueId(aweme.getOBloggerUniqueId());
            videoResponse.setCover(aweme.getOCover());
            videoResponse.setDuration(formatSecondTimeLive(aweme.getODuration()));
            LocalDateTime createDateTime = DateTimeUtils.localDateTimeBySecond(aweme.getOCreateTime());
            videoResponse.setCreateTime(createDateTime.format(DateTimeFormatter.ofPattern("MM-dd-yyyy")));
            videoResponse.setLikes(getNumber(aweme.getODiggCount()));
            videoResponse.setViews(getNumber(aweme.getOPlayCount()));
            videoResponse.setReviews(getNumber(aweme.getOCommentCount()));
            videoResponse.setShare(getNumber(aweme.getOShareCount()));
            videoResponse.setShareUrl(aweme.getOShareUrl());
            videoResponse.setScore(((int)(aweme.getScore()*10.0))/10.0);
            BigDecimal dscCount = new BigDecimal(aweme.getODiggCount()+aweme.getOShareCount()+aweme.getOCommentCount());
            BigDecimal playCount = new BigDecimal(aweme.getOPlayCount());
            videoResponse.setEngagementRate((dscCount.divide(playCount,3, RoundingMode.FLOOR).multiply(new BigDecimal(100))).setScale(1).doubleValue()+"%");
            videoResponses.add(videoResponse);
        }
        return videoResponses;
    }

    public int getVideoTotalSizeByUid(long uid){
        return bloggerService.getAwemeCountByBlogger(uid);
    }

    public String getNumber(long num) {
        return getString(num, Math.abs(num), df.format(num));
    }
    public String getNumber(double num) {
        return getString(num, Math.abs(num), df.format(num));
    }
    private String getString(double num, double abs, String format) {
        return abs >= 1.0e+9
                ? df.format((num / 1.0e+9)) + "B"
                : abs >= 1.0e+6
                ? df.format((num / 1.0e+6)) + "M"
                : abs >= 1.0e+3
                ? df.format((num / 1.0e+3)) + "K"
                : format + "";
    }

    /**
     * 获取博主粉丝画像示例数据
     * @return
     */
    public BloggerFansPortraitResponse getBloggerFansPortrait(){
        return bloggerService.getBloggerFansPortrait(getExampleBloggerId());
    }

    /**
     * 获取示例博主id
     * @return
     */
    private long getExampleBloggerId(){
        Long bloggerId;
        try{
            String bloggerIdString = redisTemplate.opsForValue().get(RedisKeysManager.INFLUENCER_BLOGGER_EXAMPLE_ID);
            if(StringUtils.isEmpty(bloggerIdString)){
                //获取示例博主配置数据
                val opt = configurationRepository.findByCfgName(EXAMPLE_BLOGGER);
                if(opt.isPresent()){
                    bloggerIdString = opt.get().getCfgValue();
                }
            }
            bloggerId = Long.parseLong(bloggerIdString);
            redisTemplate.opsForValue().set(RedisKeysManager.INFLUENCER_BLOGGER_EXAMPLE_ID,bloggerId.toString()
                    ,INFLUENCER_BLOGGER_EXAMPLE_EXPIRED_DAY,TimeUnit.DAYS);
        }catch (Exception e){
            log.error("获取示例博主数据id出错",e);
            //留个底
            bloggerId = 5831967L;
        }
        return bloggerId;
    }
    /**
     * 获取博主指标信息示例数据
     * @return
     */
    public BloggerDataResponse getBloggerData(){
        return bloggerService.getBloggerData(getExampleBloggerId(),6);
    }
    /**
     * 获取博主信息走趋示例数据
     * @return
     */
    public List<BloggerPerformanceResponse> getBloggerPerformance(){
        return bloggerService.getBloggerPerformance(getExampleBloggerId(),6);
    }
    /**
     * 获取博主视频信息走趋示例数据
     * @return
     */
    public List<AwemeResponse>  getBloggerAwemePerformance(){
        return bloggerService.getBloggerAwemePerformance(getExampleBloggerId(),6);
    }
}
